<?php
/**
 * Some basic Form Components that correspond to simple HTML tags/constructions. 
 */


class TextField extends InputTag {
	protected $type = 'text';
}


class PasswordField extends InputTag {
	protected $type = 'password';
}


class HiddenField extends InputTag {
	protected $type = 'hidden';
}


class SubmitButton extends InputTag {
	protected $type = "submit";
	public function __construct($text) {
		parent::__construct(null, $text);
	}
}


class TextAreaField extends SingleTagFormInput {
	
	private $value;
	
	public function __construct($claimed_input_name=null, $value=null) {
		parent::__construct('textarea', $claimed_input_name, $value);
	}
	
	public function set_initial_value($value) {
		$this->tag->set_contents($value);
	}
	
	public function get_initial_value() {
		return $this->tag->get_contents();
	}
	
}


class ListDropDownField extends SingleTagFormInput {
	
	private $choices;
	private $value = null;
	
	/**
	 * 
	 * @param string $claimed_input
	 * @param array $choices Mapping of code (value send to server) => User visible text 
	 */
	public function __construct($claimed_input_name, $choices=null, $value=null) {
		parent::__construct('select', $claimed_input_name, $value);
		$this->choices = $choices;
	}
	
	public function get_choices() {
		if (empty($this->choices) && $this->input instanceof MultiChoiceInput) {
			$this->choices = $this->input->get_choices();
		}
		return $this->choices;
	}
	
	public function set_initial_value($value) {
		// Attempt to detect an error as soon as possible
		if ($this->get_choices() !== null) {
			$this->check($value);
		}
		$this->value = $value;
	}
	
	private function check($value) {
		if ($this->get_choices() === null) {
			throw new Exception("No choices set yet");
		}
		if ( ! in_array($value, array_keys($this->get_choices())) ) {
			$choices = implode(',', $this->get_choices());
			throw new Exception("Value '$value' is not a possible choice; Should be one of $choices.");
		}
	}
	
	public function get_initial_value($value) {
		return $this->value;
	}
	
	public function get_js_setter() {
		$parent_setter = parent::get_js_setter();
		// TODO: There might be situations where you have '' as an actual option!
		return "
		(function (value) {
			if (value != '') {
				$parent_setter(value);
			}
			else {
				return $('#{$this->get_id()} option:first').attr('selected','selected');
			}})
	";}
	
	/**
	 * Returns the value the user actually sees, not the value (or id) 
	 * that will be sent to the server.
	 */
	public function get_js_user_value_getter() {
		return "$('#{$this->get_id()} option:selected').text";
	}
	
	public function __toString() {
		// Checks
		if ($this->get_choices() === null) {
			throw new Exception("No choices are set");
		}
		if ($this->value !== null) {
			$this->check($this->value);
		}
		
		$options = new StrArray("\n");
		$this->tag->set_contents($options);
		foreach ($this->get_choices() as $code => $choice) {
			$tag = new Tag('option');
			$tag->set_attr('value', $code);
			if ($this->value == $code) {
				$tag->add_prop('selected');
			}
			// TODO: add a better fix for unicode support. This only supports &#---; codes
			$tag->set_contents(str_replace('&amp;#', '&#', htmlentities($choice)));
			$options[] = $tag;
		}

		return parent::__toString();
	}
	
}


/*
 * This is not for direct use: it is wrapped in a formcomposite
 * in order to let it send a 0 or 1 to the server
 */
class _CheckboxField extends InputTag {
	
	protected $type = 'checkbox';
	
	public function set_initial_value($value) {
		if ($value) {
			$this->add_prop('checked');
		}
		else {
			$this->remove_prop('checked');
		}
	}
	
	public function get_initial_value() {
		throw new Exception("Not implemented");
	}
	
}


class CheckboxField extends DoubleTagFormInput implements FormInput {
	
	public function __construct($claimend_input_name=null) {
		parent::__construct(
			new _CheckboxField(),
			new HiddenField($claimend_input_name)
		);
		
		$visible_element = $this->get_visible()->get_js_elem();
		$setter = $this->get_main()->get_js_setter();
		$this->add_js_preprocessing("
			$setter(Number($visible_element.is(':checked')));
		");
	}	
	
}


class JavascriptBlock extends FormComposite {
	
	public function __construct($code='') {
		parent::__construct();
		$this->add('script_start_tag', '<script type="text/javascript"><!--');
		$this->add('script_content', remove_empty_lines($code));
		$this->add('script_end_tag', '//--></script>');
	}
	
	public function add_code($code) {
		$this->c['script_content'] .= $code;
	}
	
}

